from backend.core.db.connection import db
#from backend.core.db.types import Model

class Query(object):

    def __init__(self, type='SELECT', conditions={}, model=None):

        self.type = type
        self.conditions = conditions
        self.order = ''
        self.limit = ()
        if not issubclass(model, Model):
            raise Exception('Query object was pass an invalid model')
        self.model = model

    def __getitem__(self, k):

        if isinstance(k, (int, long)):
            self.limit = (k, 1)
            return self.get_data()[0]
        elif isinstance(k, slice):
            if k.start is not None:
                assert k.stop is not None, 'Limit must be set when an offset is present'
                self.limit = k.start, k.stop
            elif k.stop is not None:
                self.limit = 0, k.stop

        return self.get_data()

    def __len__(self):
        return len(self.get_data())

    def __iter__(self):
        return iter(self.get_data())

    def __repr__(self):
        return repr(self.get_data())

    def count(self):

        self.type = 'SELECT COUNT(*)'
        return self.execute_query().fetchone()[0]

    def filter(self, **kwargs):
        self.conditions.update(kwargs)
        return self

    def order_by(self, field, direction='ASC'):
        self.order = 'ORDER BY %s %s' % (field, direction)
        return self

    def extract_condition_keys(self):
        if len(self.conditions):
            where = ' AND '.join(['%s=%%s' % x for x,y in self.conditions.iteritems()])
            return 'WHERE %s' % where

    def extract_condition_values(self):
        return list(self.conditions.itervalues())

    def query_template(self):
        return '%s FROM %s %s %s %s' % (
            self.type,
            self.model.Meta.table,
            self.extract_condition_keys() or '',
            self.order,
            self.extract_limit() or '',
        )

    def extract_limit(self):
        if len(self.limit):
            return 'LIMIT %s' % ', '.join([str(l) for l in self.limit])
        return ''

    def get_data(self):
        return list(self.iterator())

    def iterator(self):
        result = self.execute_query()

        for row in result.fetchall():
            obj = self.model(*row)
            obj._new_record = False
            yield obj

    @classmethod
    def execute_query(self):
        values = self.extract_condition_values()
        return db.cursor.execute(self.query_template(), values)

    @classmethod
    def sql(self, sql, values=()):
        result = Query.raw_sql(sql, values)
        fields = [f[0] for f in result.fetchall()]
        return [dict(zip(fields, row)) for row in result.fetchall()]

    @classmethod
    def get_fields(self, table): pass

    @classmethod
    def raw_sql(self, sql, values=()):
        #FIXME: Remove this debugging output as soon as everything is completed
        #print sql
        #print values
        #import pdb
        #pdb.set_trace()
        db.cursor.execute(sql, values)
        ref = db.cursor
        return ref

